"""
基于角色的访问控制(RBAC)路由模块
提供用户管理、敏感词管理和语料库管理功能，仅限管理员访问
"""
import os
import re
from datetime import datetime
from typing import List
from flask import Blueprint, request, jsonify
from werkzeug.utils import secure_filename
from models import User, SensitiveWord, SentencePair, db
from utils.text_auth import admin_required, validate_email, validate_password, AuthManager
from sqlalchemy import or_

# 创建RBAC蓝图
rbac_bp = Blueprint('rbac', __name__)

ALLOWED_LANGUAGE_CODES = {'zh', 'en', 'vi', 'th', 'id', 'ms'}
ALLOWED_STATUS_VALUES = {'pending', 'approved', 'rejected'}
ALLOWED_SOURCE_VALUES = {'manual', 'auto', 'llm', 'admin_upload', 'admin_create'}
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'


def parse_datetime_value(value):
    """
    将字符串或时间戳转换为 datetime 对象。
    支持格式:
      - YYYY-MM-DD HH:MM:SS
      - ISO 8601 字符串 (含 T、时区)
      - UNIX 时间戳（秒）
    """
    if value is None or value == '':
        return None

    if isinstance(value, datetime):
        return value

    if isinstance(value, (int, float)):
        return datetime.fromtimestamp(value)

    if isinstance(value, str):
        normalized = value.strip()
        if not normalized:
            return None
        try:
            return datetime.strptime(normalized, DATETIME_FORMAT)
        except ValueError:
            try:
                iso_value = normalized.replace('Z', '+00:00') if normalized.endswith('Z') else normalized
                return datetime.fromisoformat(iso_value)
            except ValueError:
                pass

    raise ValueError('创建时间格式无效，请使用 YYYY-MM-DD HH:mm:ss 格式')


@rbac_bp.route('/users', methods=['GET'])
@admin_required
def get_users(current_user):
    """
    获取用户列表接口（管理员专用）
    
    查询参数:
        page (int): 页码，默认1
        per_page (int): 每页数量，默认10
        search (str): 搜索关键词（用户名或邮箱）
        role (str): 角色筛选
        
    返回:
        JSON: 用户列表和分页信息
    """
    try:
        # 获取查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)
        search = request.args.get('search', '').strip()
        role_filter = request.args.get('role', '').strip()
        
        # 限制每页数量
        per_page = min(per_page, 100)
        
        # 构建查询
        query = User.query
        
        # 搜索过滤
        if search:
            query = query.filter(
                or_(
                    User.username.contains(search),
                    User.email.contains(search)
                )
            )
        
        # 角色过滤
        if role_filter and role_filter in ['user', 'admin']:
            query = query.filter(User.role == role_filter)
        
        # 分页查询
        pagination = query.paginate(
            page=page,
            per_page=per_page,
            error_out=False
        )
        
        users = []
        for user in pagination.items:
            users.append({
                'id': user.id,
                'username': user.username,
                'email': user.email,
                'role': user.role,
                'created_at': user.created_at.isoformat()
            })
        
        return jsonify({
            'users': users,
            'pagination': {
                'page': page,
                'per_page': per_page,
                'total': pagination.total,
                'pages': pagination.pages,
                'has_prev': pagination.has_prev,
                'has_next': pagination.has_next
            }
        }), 200
        
    except Exception as e:
        return jsonify({'message': f'获取用户列表失败: {str(e)}'}), 500


@rbac_bp.route('/users/<int:user_id>', methods=['GET'])
@admin_required
def get_user(current_user, user_id):
    """
    获取指定用户信息接口（管理员专用）
    
    路径参数:
        user_id (int): 用户ID
        
    返回:
        JSON: 用户详细信息
    """
    try:
        user = User.query.get(user_id)
        if not user:
            return jsonify({'message': '用户不存在'}), 404
        
        return jsonify({
            'user': {
                'id': user.id,
                'username': user.username,
                'email': user.email,
                'role': user.role,
                'created_at': user.created_at.isoformat()
            }
        }), 200
        
    except Exception as e:
        return jsonify({'message': f'获取用户信息失败: {str(e)}'}), 500


@rbac_bp.route('/users/<int:user_id>/role', methods=['PUT'])
@admin_required
def update_user_role(current_user, user_id):
    """
    更新用户角色接口（管理员专用）
    
    路径参数:
        user_id (int): 用户ID
        
    请求体参数:
        role (str): 新角色 ('user' 或 'admin')
        
    返回:
        JSON: 更新结果
    """
    try:
        data = request.get_json()
        
        if not data or 'role' not in data:
            return jsonify({'message': '缺少角色参数'}), 400
        
        new_role = data['role']
        if new_role not in ['user', 'admin']:
            return jsonify({'message': '角色必须是 user 或 admin'}), 400
        
        # 查找用户
        user = User.query.get(user_id)
        if not user:
            return jsonify({'message': '用户不存在'}), 404
        
        # 防止管理员修改自己的角色
        if user.id == current_user.id:
            return jsonify({'message': '不能修改自己的角色'}), 403
        
        # 更新角色
        user.role = new_role
        db.session.commit()
        
        return jsonify({
            'message': '用户角色更新成功',
            'user': {
                'id': user.id,
                'username': user.username,
                'email': user.email,
                'role': user.role
            }
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'更新用户角色失败: {str(e)}'}), 500


@rbac_bp.route('/users/<int:user_id>', methods=['DELETE'])
@admin_required
def delete_user(current_user, user_id):
    """
    删除用户接口（管理员专用）
    
    路径参数:
        user_id (int): 用户ID
        
    返回:
        JSON: 删除结果
    """
    try:
        # 查找用户
        user = User.query.get(user_id)
        if not user:
            return jsonify({'message': '用户不存在'}), 404
        
        # 防止管理员删除自己
        if user.id == current_user.id:
            return jsonify({'message': '不能删除自己的账号'}), 403
        
        # 删除用户
        db.session.delete(user)
        db.session.commit()
        
        return jsonify({'message': '用户删除成功'}), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'删除用户失败: {str(e)}'}), 500


@rbac_bp.route('/sensitive-words', methods=['GET'])
@admin_required
def get_sensitive_words(current_user):
    """
    获取敏感词列表接口（管理员专用）
    
    查询参数:
        page (int): 页码，默认1
        per_page (int): 每页数量，默认20
        search (str): 搜索关键词
        
    返回:
        JSON: 敏感词列表和分页信息
    """
    try:
        # 获取查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 20, type=int)
        search = request.args.get('search', '').strip()
        
        # 限制每页数量
        per_page = min(per_page, 100)
        
        # 构建查询
        query = SensitiveWord.query
        
        # 搜索过滤
        if search:
            query = query.filter(SensitiveWord.word.contains(search))
        
        # 分页查询
        pagination = query.paginate(
            page=page,
            per_page=per_page,
            error_out=False
        )
        
        words = []
        for word in pagination.items:
            words.append({
                'id': word.id,
                'word': word.word
            })
        
        return jsonify({
            'sensitive_words': words,
            'pagination': {
                'page': page,
                'per_page': per_page,
                'total': pagination.total,
                'pages': pagination.pages,
                'has_prev': pagination.has_prev,
                'has_next': pagination.has_next
            }
        }), 200
        
    except Exception as e:
        return jsonify({'message': f'获取敏感词列表失败: {str(e)}'}), 500


@rbac_bp.route('/sensitive-words', methods=['POST'])
@admin_required
def add_sensitive_word(current_user):
    """
    添加敏感词接口（管理员专用）
    
    请求体参数:
        word (str): 敏感词
        
    返回:
        JSON: 添加结果
    """
    try:
        data = request.get_json()
        
        if not data or 'word' not in data:
            return jsonify({'message': '缺少敏感词参数'}), 400
        
        word = data['word'].strip()
        if not word:
            return jsonify({'message': '敏感词不能为空'}), 400
        
        # 检查敏感词是否已存在
        existing_word = SensitiveWord.query.filter_by(word=word).first()
        if existing_word:
            return jsonify({'message': '敏感词已存在'}), 409
        
        # 添加敏感词
        new_word = SensitiveWord(word=word)
        db.session.add(new_word)
        db.session.commit()
        
        return jsonify({
            'message': '敏感词添加成功',
            'sensitive_word': {
                'id': new_word.id,
                'word': new_word.word
            }
        }), 201
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'添加敏感词失败: {str(e)}'}), 500


@rbac_bp.route('/sensitive-words/<int:word_id>', methods=['PUT'])
@admin_required
def update_sensitive_word(current_user, word_id):
    """
    更新敏感词接口（管理员专用）
    
    路径参数:
        word_id (int): 敏感词ID
        
    请求体参数:
        word (str): 新的敏感词
        
    返回:
        JSON: 更新结果
    """
    try:
        data = request.get_json()
        
        if not data or 'word' not in data:
            return jsonify({'message': '缺少敏感词参数'}), 400
        
        new_word = data['word'].strip()
        if not new_word:
            return jsonify({'message': '敏感词不能为空'}), 400
        
        # 查找敏感词
        sensitive_word = SensitiveWord.query.get(word_id)
        if not sensitive_word:
            return jsonify({'message': '敏感词不存在'}), 404
        
        # 检查新敏感词是否已存在
        existing_word = SensitiveWord.query.filter_by(word=new_word).first()
        if existing_word and existing_word.id != word_id:
            return jsonify({'message': '敏感词已存在'}), 409
        
        # 更新敏感词
        sensitive_word.word = new_word
        db.session.commit()
        
        return jsonify({
            'message': '敏感词更新成功',
            'sensitive_word': {
                'id': sensitive_word.id,
                'word': sensitive_word.word
            }
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'更新敏感词失败: {str(e)}'}), 500


@rbac_bp.route('/sensitive-words/<int:word_id>', methods=['DELETE'])
@admin_required
def delete_sensitive_word(current_user, word_id):
    """
    删除敏感词接口（管理员专用）
    
    路径参数:
        word_id (int): 敏感词ID
        
    返回:
        JSON: 删除结果
    """
    try:
        # 查找敏感词
        sensitive_word = SensitiveWord.query.get(word_id)
        if not sensitive_word:
            return jsonify({'message': '敏感词不存在'}), 404
        
        # 删除敏感词
        db.session.delete(sensitive_word)
        db.session.commit()
        
        return jsonify({'message': '敏感词删除成功'}), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'删除敏感词失败: {str(e)}'}), 500


@rbac_bp.route('/sensitive-words/batch', methods=['POST'])
@admin_required
def batch_add_sensitive_words(current_user):
    """
    批量添加敏感词接口（管理员专用）
    
    请求体参数:
        words (list): 敏感词列表
        
    返回:
        JSON: 批量添加结果
    """
    try:
        data = request.get_json()
        
        if not data or 'words' not in data or not isinstance(data['words'], list):
            return jsonify({'message': '缺少敏感词列表参数'}), 400
        
        words = [word.strip() for word in data['words'] if word.strip()]
        if not words:
            return jsonify({'message': '敏感词列表不能为空'}), 400
        
        # 检查重复
        existing_words = set(word.word for word in SensitiveWord.query.filter(SensitiveWord.word.in_(words)).all())
        new_words = [word for word in words if word not in existing_words]
        
        # 批量添加
        if new_words:
            sensitive_words = [SensitiveWord(word=word) for word in new_words]
            db.session.add_all(sensitive_words)
            db.session.commit()
        
        return jsonify({
            'message': f'成功添加 {len(new_words)} 个敏感词',
            'added_count': len(new_words),
            'duplicate_count': len(words) - len(new_words),
            'duplicates': list(existing_words & set(words))
        }), 201
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'批量添加敏感词失败: {str(e)}'}), 500


# ==================== 语料库管理功能 ====================

# 配置上传文件夹
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)


def get_sensitive_words_for_filter() -> List[str]:
    """从数据库获取敏感词列表用于过滤"""
    try:
        sensitive_words = SensitiveWord.query.all()
        return [word.word for word in sensitive_words]
    except Exception as e:
        print(f"获取敏感词失败: {e}")
        return []


def filter_sensitive_words(text: str, sensitive_words: List[str]) -> str:
    """
    过滤文本中的敏感词
    
    Args:
        text: 原始文本
        sensitive_words: 敏感词列表
        
    Returns:
        过滤后的文本（敏感词用***替换）
    """
    filtered_text = text
    for word in sensitive_words:
        if word in filtered_text:
            filtered_text = filtered_text.replace(word, '*' * len(word))
    return filtered_text


def clean_text_for_admin(text: str, sensitive_words: List[str] = None) -> str:
    """清洗文本，去除特殊字符和多余空格，并过滤敏感词"""
    # 去除多余空格
    text = re.sub(r'\s+', ' ', text)
    # 去除控制字符
    text = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', text)
    # 去除首尾空格
    text = text.strip()
    
    # 过滤敏感词
    if sensitive_words:
        text = filter_sensitive_words(text, sensitive_words)
    
    return text


def process_admin_corpus_file(filepath: str, uploaded_by: int) -> dict:
    """
    处理管理员上传的语料库文件
    
    Args:
        filepath: 文件路径
        uploaded_by: 上传用户ID
        
    Returns:
        处理结果字典
    """
    try:
        # 获取敏感词列表
        sensitive_words = get_sensitive_words_for_filter()
        
        with open(filepath, 'r', encoding='utf-8') as file:
            lines = file.readlines()
        
        processed_pairs = []
        total_lines = len(lines)
        invalid_lines = 0
        
        for line_num, line in enumerate(lines, 1):
            line = line.strip()
            if not line:
                continue
                
            # 解析句子对格式: lang1:text1|||lang2:text2
            if '|||' not in line:
                print(f"第{line_num}行格式错误，跳过: {line[:50]}")
                invalid_lines += 1
                continue
            
            try:
                parts = line.split('|||')
                if len(parts) != 2:
                    print(f"第{line_num}行分割错误，跳过: {line[:50]}")
                    invalid_lines += 1
                    continue
                
                # 解析第一部分: lang1:text1
                left_part = parts[0].strip()
                if ':' not in left_part:
                    print(f"第{line_num}行左侧格式错误，跳过: {left_part[:50]}")
                    invalid_lines += 1
                    continue
                
                lang1, text1 = left_part.split(':', 1)
                lang1 = lang1.strip()
                text1 = clean_text_for_admin(text1.strip(), sensitive_words)
                
                # 解析第二部分: lang2:text2
                right_part = parts[1].strip()
                if ':' not in right_part:
                    print(f"第{line_num}行右侧格式错误，跳过: {right_part[:50]}")
                    invalid_lines += 1
                    continue
                
                lang2, text2 = right_part.split(':', 1)
                lang2 = lang2.strip()
                text2 = clean_text_for_admin(text2.strip(), sensitive_words)
                
                # 验证数据
                if not all([lang1, text1, lang2, text2]):
                    print(f"第{line_num}行数据不完整，跳过")
                    invalid_lines += 1
                    continue
                
                if len(text1) > 1000 or len(text2) > 1000:
                    print(f"第{line_num}行文本过长，跳过")
                    invalid_lines += 1
                    continue
                
                processed_pairs.append({
                    'lang1': lang1,
                    'text1': text1,
                    'lang2': lang2,
                    'text2': text2,
                    'uploaded_by': uploaded_by
                })
                
            except Exception as e:
                print(f"第{line_num}行处理错误: {e}")
                invalid_lines += 1
                continue
        
        cleaned_lines = len(processed_pairs)
        
        return {
            'processed': processed_pairs,
            'total_lines': total_lines,
            'cleaned_lines': cleaned_lines,
            'invalid_lines': invalid_lines
        }
        
    except Exception as e:
        raise ValueError(f"文件处理失败: {str(e)}")


@rbac_bp.route('/corpus/upload', methods=['POST'])
@admin_required
def admin_upload_corpus(current_user):
    """
    管理员上传语料库接口
    
    表单参数:
        file: 上传的语料库文件(.txt格式)
        
    返回:
        JSON: 上传和处理结果
    """
    try:
        # 检查请求中是否有文件
        if 'file' not in request.files:
            return jsonify({'message': '未上传文件'}), 400
            
        file = request.files['file']
        
        # 检查文件名是否为空
        if file.filename == '':
            return jsonify({'message': '文件名为空'}), 400
            
        # 检查文件扩展名
        if not file.filename.endswith('.txt'):
            return jsonify({'message': '仅支持 .txt 文件'}), 400

        # 保存文件
        filename = secure_filename(file.filename)
        filepath = os.path.join(UPLOAD_FOLDER, filename)
        file.save(filepath)

        try:
            # 处理文件内容
            result = process_admin_corpus_file(filepath, current_user.id)
            
            # 批量入库，管理员上传的语料库默认状态为approved
            for item in result['processed']:
                pair = SentencePair(
                    lang1=item['lang1'],
                    text1=item['text1'],
                    lang2=item['lang2'],
                    text2=item['text2'],
                    source='admin_upload',
                    status='approved',  # 管理员上传默认为approved状态
                    uploaded_by=item['uploaded_by']
                )
                db.session.add(pair)
                
            db.session.commit()
            
            return jsonify({
                'message': f'管理员语料库上传成功，已自动审核通过 {result["cleaned_lines"]} 条句子对',
                'count': result["cleaned_lines"],
                'total_lines': result["total_lines"],
                'cleaned_lines': result["cleaned_lines"],
                'invalid_lines': result["invalid_lines"],
                'status': 'approved'
            }), 201
            
        except ValueError as e:
            db.session.rollback()
            return jsonify({'message': str(e)}), 400
            
        except Exception as e:
            db.session.rollback()
            return jsonify({'message': f'服务器内部错误: {str(e)}'}), 500
            
        finally:
            # 清理临时文件
            if os.path.exists(filepath):
                os.remove(filepath)
                
    except Exception as e:
        return jsonify({'message': f'上传失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs', methods=['GET'])
@admin_required
def get_sentence_pairs(current_user):
    """
    获取句子对列表接口（管理员专用）
    
    查询参数:
        page (int): 页码，默认1
        per_page (int): 每页数量，默认20
        search (str): 搜索关键词（文本内容）
        lang1 (str): 第一种语言筛选
        lang2 (str): 第二种语言筛选
        status (str): 状态筛选 (pending/approved/rejected)
        source (str): 来源筛选 (manual/admin_upload)
        
    返回:
        JSON: 句子对列表和分页信息
    """
    try:
        # 获取查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 20, type=int)
        search = request.args.get('search', '').strip()
        lang1_filter = request.args.get('lang1', '').strip()
        lang2_filter = request.args.get('lang2', '').strip()
        status_filter = request.args.get('status', '').strip()
        source_filter = request.args.get('source', '').strip()
        
        # 限制每页数量
        per_page = min(per_page, 100)
        
        # 构建查询
        query = SentencePair.query
        
        # 搜索过滤
        if search:
            query = query.filter(
                or_(
                    SentencePair.text1.contains(search),
                    SentencePair.text2.contains(search)
                )
            )
        
        # 语言过滤
        if lang1_filter:
            query = query.filter(SentencePair.lang1 == lang1_filter)
        if lang2_filter:
            query = query.filter(SentencePair.lang2 == lang2_filter)
            
        # 状态过滤
        if status_filter and status_filter in ['pending', 'approved', 'rejected']:
            query = query.filter(SentencePair.status == status_filter)
            
        # 来源过滤
        if source_filter:
            query = query.filter(SentencePair.source == source_filter)
        
        # 按创建时间倒序排列
        query = query.order_by(SentencePair.created_at.desc())
        
        # 分页查询
        pagination = query.paginate(
            page=page,
            per_page=per_page,
            error_out=False
        )
        
        sentence_pairs = []
        for pair in pagination.items:
            # 获取上传用户信息
            uploader = None
            if pair.uploaded_by:
                user = User.query.get(pair.uploaded_by)
                if user:
                    uploader = {
                        'id': user.id,
                        'username': user.username
                    }
            
            sentence_pairs.append({
                'id': pair.id,
                'lang1': pair.lang1,
                'text1': pair.text1,
                'lang2': pair.lang2,
                'text2': pair.text2,
                'source': pair.source,
                'status': pair.status,
                'uploaded_by': pair.uploaded_by,
                'uploader': uploader,
                'created_at': pair.created_at.isoformat()
            })
        
        return jsonify({
            'sentence_pairs': sentence_pairs,
            'pagination': {
                'page': page,
                'per_page': per_page,
                'total': pagination.total,
                'pages': pagination.pages,
                'has_prev': pagination.has_prev,
                'has_next': pagination.has_next
            }
        }), 200
        
    except Exception as e:
        return jsonify({'message': f'获取句子对列表失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs/<int:pair_id>', methods=['GET'])
@admin_required
def get_sentence_pair(current_user, pair_id):
    """
    获取指定句子对信息接口（管理员专用）
    
    路径参数:
        pair_id (int): 句子对ID
        
    返回:
        JSON: 句子对详细信息
    """
    try:
        pair = SentencePair.query.get(pair_id)
        if not pair:
            return jsonify({'message': '句子对不存在'}), 404
        
        # 获取上传用户信息
        uploader = None
        if pair.uploaded_by:
            user = User.query.get(pair.uploaded_by)
            if user:
                uploader = {
                    'id': user.id,
                    'username': user.username,
                    'email': user.email
                }
        
        return jsonify({
            'sentence_pair': {
                'id': pair.id,
                'lang1': pair.lang1,
                'text1': pair.text1,
                'lang2': pair.lang2,
                'text2': pair.text2,
                'source': pair.source,
                'status': pair.status,
                'uploaded_by': pair.uploaded_by,
                'uploader': uploader,
                'created_at': pair.created_at.isoformat()
            }
        }), 200
        
    except Exception as e:
        return jsonify({'message': f'获取句子对信息失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs', methods=['POST'])
@admin_required
def create_sentence_pair(current_user):
    """
    创建句子对接口（管理员专用）
    
    请求体参数:
        lang1 (str): 第一种语言代码
        text1 (str): 第一种语言文本
        lang2 (str): 第二种语言代码
        text2 (str): 第二种语言文本
        status (str): 状态，可选，默认approved
        source (str): 来源，可选，默认admin_create
        
    返回:
        JSON: 创建结果
    """
    try:
        data = request.get_json()
        
        if not data:
            return jsonify({'message': '缺少请求数据'}), 400
        
        # 验证必需字段
        required_fields = ['lang1', 'text1', 'lang2', 'text2']
        for field in required_fields:
            if field not in data or not str(data[field]).strip():
                return jsonify({'message': f'缺少必需字段: {field}'}), 400

        pair_id = data.get('id')
        if pair_id not in (None, ''):
            try:
                pair_id = int(pair_id)
            except (TypeError, ValueError):
                return jsonify({'message': '句子对ID必须为正整数'}), 400
            if pair_id <= 0:
                return jsonify({'message': '句子对ID必须为正整数'}), 400
            if SentencePair.query.get(pair_id):
                return jsonify({'message': '句子对ID已存在，请使用其他ID'}), 400
        else:
            pair_id = None

        lang1 = data['lang1'].strip()
        lang2 = data['lang2'].strip()
        if lang1 not in ALLOWED_LANGUAGE_CODES:
            return jsonify({'message': f'lang1 必须为以下值之一: {", ".join(sorted(ALLOWED_LANGUAGE_CODES))}'}), 400
        if lang2 not in ALLOWED_LANGUAGE_CODES:
            return jsonify({'message': f'lang2 必须为以下值之一: {", ".join(sorted(ALLOWED_LANGUAGE_CODES))}'}), 400

        text1 = data['text1'].strip()
        text2 = data['text2'].strip()
        if len(text1) > 1000 or len(text2) > 1000:
            return jsonify({'message': '文本长度不能超过1000个字符'}), 400

        status = data.get('status', 'approved').strip()
        if status not in ALLOWED_STATUS_VALUES:
            return jsonify({'message': '状态必须是 pending、approved 或 rejected'}), 400

        source = data.get('source', 'manual').strip()
        if source not in ALLOWED_SOURCE_VALUES:
            return jsonify({'message': f'来源必须为以下值之一: {", ".join(sorted(ALLOWED_SOURCE_VALUES))}'}), 400

        uploaded_by_value = data.get('uploaded_by', current_user.id)
        try:
            uploaded_by = int(uploaded_by_value)
        except (TypeError, ValueError):
            return jsonify({'message': '上传者ID必须为正整数'}), 400
        if uploaded_by <= 0:
            return jsonify({'message': '上传者ID必须为正整数'}), 400

        uploader = User.query.get(uploaded_by)
        if not uploader:
            return jsonify({'message': '指定的上传者不存在'}), 400

        created_at_value = data.get('created_at')
        if created_at_value:
            try:
                created_at = parse_datetime_value(created_at_value)
            except ValueError as exc:
                return jsonify({'message': str(exc)}), 400
        else:
            created_at = datetime.utcnow()

        # 获取敏感词并过滤
        sensitive_words = get_sensitive_words_for_filter()
        text1 = clean_text_for_admin(text1, sensitive_words)
        text2 = clean_text_for_admin(text2, sensitive_words)

        # 创建句子对
        new_pair = SentencePair(
            id=pair_id,
            lang1=lang1,
            text1=text1,
            lang2=lang2,
            text2=text2,
            source=source,
            status=status,
            uploaded_by=uploaded_by,
            created_at=created_at
        )

        db.session.add(new_pair)
        db.session.commit()
        
        return jsonify({
            'message': '句子对创建成功',
            'sentence_pair': {
                'id': new_pair.id,
                'lang1': new_pair.lang1,
                'text1': new_pair.text1,
                'lang2': new_pair.lang2,
                'text2': new_pair.text2,
                'source': new_pair.source,
                'status': new_pair.status,
                'uploaded_by': new_pair.uploaded_by,
                'created_at': new_pair.created_at.isoformat()
            }
        }), 201
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'创建句子对失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs/<int:pair_id>', methods=['PUT'])
@admin_required
def update_sentence_pair(current_user, pair_id):
    """
    更新句子对接口（管理员专用）
    
    路径参数:
        pair_id (int): 句子对ID
        
    请求体参数:
        lang1 (str): 第一种语言代码，可选
        text1 (str): 第一种语言文本，可选
        lang2 (str): 第二种语言代码，可选
        text2 (str): 第二种语言文本，可选
        status (str): 状态，可选
        source (str): 来源，可选
        
    返回:
        JSON: 更新结果
    """
    try:
        data = request.get_json()
        
        if not data:
            return jsonify({'message': '缺少请求数据'}), 400
        
        # 查找句子对
        pair = SentencePair.query.get(pair_id)
        if not pair:
            return jsonify({'message': '句子对不存在'}), 404
        
        # 获取敏感词列表
        sensitive_words = get_sensitive_words_for_filter()
        
        # 更新字段
        if 'lang1' in data and data['lang1'].strip():
            lang1 = data['lang1'].strip()
            if lang1 not in ALLOWED_LANGUAGE_CODES:
                return jsonify({'message': f'lang1 必须为以下值之一: {", ".join(sorted(ALLOWED_LANGUAGE_CODES))}'}), 400
            pair.lang1 = lang1
        
        if 'text1' in data and data['text1'].strip():
            text1 = data['text1'].strip()
            if len(text1) > 1000:
                return jsonify({'message': 'text1长度不能超过1000个字符'}), 400
            pair.text1 = clean_text_for_admin(text1, sensitive_words)
        
        if 'lang2' in data and data['lang2'].strip():
            lang2 = data['lang2'].strip()
            if lang2 not in ALLOWED_LANGUAGE_CODES:
                return jsonify({'message': f'lang2 必须为以下值之一: {", ".join(sorted(ALLOWED_LANGUAGE_CODES))}'}), 400
            pair.lang2 = lang2
        
        if 'text2' in data and data['text2'].strip():
            text2 = data['text2'].strip()
            if len(text2) > 1000:
                return jsonify({'message': 'text2长度不能超过1000个字符'}), 400
            pair.text2 = clean_text_for_admin(text2, sensitive_words)
        
        if 'status' in data and data['status'].strip():
            status = data['status'].strip()
            if status not in ALLOWED_STATUS_VALUES:
                return jsonify({'message': '状态必须是 pending、approved 或 rejected'}), 400
            pair.status = status
        
        if 'source' in data and data['source'].strip():
            source = data['source'].strip()
            if source not in ALLOWED_SOURCE_VALUES:
                return jsonify({'message': f'来源必须为以下值之一: {", ".join(sorted(ALLOWED_SOURCE_VALUES))}'}), 400
            pair.source = source

        if 'uploaded_by' in data:
            if data['uploaded_by'] in (None, ''):
                return jsonify({'message': '上传者ID为必填项'}), 400
            try:
                uploaded_by = int(data['uploaded_by'])
            except (TypeError, ValueError):
                return jsonify({'message': '上传者ID必须为正整数'}), 400
            if uploaded_by <= 0:
                return jsonify({'message': '上传者ID必须为正整数'}), 400
            uploader = User.query.get(uploaded_by)
            if not uploader:
                return jsonify({'message': '指定的上传者不存在'}), 400
            pair.uploaded_by = uploaded_by

        if 'created_at' in data and data['created_at']:
            try:
                pair.created_at = parse_datetime_value(data['created_at'])
            except ValueError as exc:
                return jsonify({'message': str(exc)}), 400
        
        db.session.commit()
        
        return jsonify({
            'message': '句子对更新成功',
            'sentence_pair': {
                'id': pair.id,
                'lang1': pair.lang1,
                'text1': pair.text1,
                'lang2': pair.lang2,
                'text2': pair.text2,
                'source': pair.source,
                'status': pair.status,
                'uploaded_by': pair.uploaded_by,
                'created_at': pair.created_at.isoformat()
            }
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'更新句子对失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs/<int:pair_id>', methods=['DELETE'])
@admin_required
def delete_sentence_pair(current_user, pair_id):
    """
    删除句子对接口（管理员专用）
    
    路径参数:
        pair_id (int): 句子对ID
        
    返回:
        JSON: 删除结果
    """
    try:
        # 查找句子对
        pair = SentencePair.query.get(pair_id)
        if not pair:
            return jsonify({'message': '句子对不存在'}), 404
        
        # 删除句子对
        db.session.delete(pair)
        db.session.commit()
        
        return jsonify({'message': '句子对删除成功'}), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'删除句子对失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs/batch-update-status', methods=['PUT'])
@admin_required
def batch_update_sentence_pairs_status(current_user):
    """
    批量更新句子对状态接口（管理员专用）
    
    请求体参数:
        pair_ids (list): 句子对ID列表
        status (str): 新状态 (pending/approved/rejected)
        
    返回:
        JSON: 批量更新结果
    """
    try:
        data = request.get_json()
        
        if not data or 'pair_ids' not in data or 'status' not in data:
            return jsonify({'message': '缺少必需参数'}), 400
        
        pair_ids = data['pair_ids']
        new_status = data['status'].strip()
        
        if not isinstance(pair_ids, list) or not pair_ids:
            return jsonify({'message': '句子对ID列表不能为空'}), 400
        
        if new_status not in ['pending', 'approved', 'rejected']:
            return jsonify({'message': '状态必须是 pending、approved 或 rejected'}), 400
        
        # 查找并更新句子对
        pairs = SentencePair.query.filter(SentencePair.id.in_(pair_ids)).all()
        
        if not pairs:
            return jsonify({'message': '未找到指定的句子对'}), 404
        
        updated_count = 0
        for pair in pairs:
            pair.status = new_status
            updated_count += 1
        
        db.session.commit()
        
        return jsonify({
            'message': f'成功更新 {updated_count} 个句子对的状态为 {new_status}',
            'updated_count': updated_count,
            'status': new_status
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'批量更新句子对状态失败: {str(e)}'}), 500


@rbac_bp.route('/sentence-pairs/batch-delete', methods=['DELETE'])
@admin_required
def batch_delete_sentence_pairs(current_user):
    """
    批量删除句子对接口（管理员专用）
    
    请求体参数:
        pair_ids (list): 句子对ID列表
        
    返回:
        JSON: 批量删除结果
    """
    try:
        data = request.get_json()
        
        if not data or 'pair_ids' not in data:
            return jsonify({'message': '缺少句子对ID列表参数'}), 400
        
        pair_ids = data['pair_ids']
        
        if not isinstance(pair_ids, list) or not pair_ids:
            return jsonify({'message': '句子对ID列表不能为空'}), 400
        
        # 查找并删除句子对
        pairs = SentencePair.query.filter(SentencePair.id.in_(pair_ids)).all()
        
        if not pairs:
            return jsonify({'message': '未找到指定的句子对'}), 404
        
        deleted_count = len(pairs)
        for pair in pairs:
            db.session.delete(pair)
        
        db.session.commit()
        
        return jsonify({
            'message': f'成功删除 {deleted_count} 个句子对',
            'deleted_count': deleted_count
        }), 200
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'message': f'批量删除句子对失败: {str(e)}'}), 500
